using System;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Collections.Generic;

namespace Dida
{
	public interface IInputField
	{
		void Update(float timeDelta);
	}

	public interface IVector2DInput : IInputField
	{		
		Vector2D Value { get; }
	}

	public interface IButtonStateInput : IInputField
	{
		bool State { get; }
	}

	public class KeyboardInputVector : IVector2DInput
	{
		char left;
		char right;
		char up;
		char down;

		Vector2D value;

		[DllImport("User32.dll")]
		private static extern short GetAsyncKeyState(int keyCode);

		public KeyboardInputVector(char left, char right, char up, char down)
		{
			this.left = left;
			this.right = right;
			this.up = up;
			this.down = down;
		}

		public void Update(float timeDelta)
		{
			value.Set(0,0);
			if (GetAsyncKeyState(left) < 0)
				value.x--;
			if (GetAsyncKeyState(right) < 0)
				value.x++;
			if (GetAsyncKeyState(up) < 0)
				value.y--;
			if (GetAsyncKeyState(down) < 0)
				value.y++;
			if (value.SqrLen > .1f)
				value.Normalize();
		}

		public Vector2D Value
		{
			get { return value; }
		}
	}

	[AttributeUsage(AttributeTargets.Field,AllowMultiple=false)]
	public class InputFieldAttribute : Attribute
	{
	}

	[AttributeUsage(AttributeTargets.Field,AllowMultiple=false)]
	public class ChildInputContainerAttribute : Attribute
	{
	}
	
	public abstract class InputContainer
	{
		private List<FieldInfo> inputFields = new List<FieldInfo>();
		private List<FieldInfo> childContainerFields = new List<FieldInfo>();

		public InputContainer()
		{
			Type type = GetType();
			foreach (FieldInfo field in type.GetFields())
			{
				Type[] interfaces = field.GetType().GetInterfaces();
				if(Array.IndexOf(interfaces,typeof(IInputField)) == -1)
				{
					inputFields.Add(field);
				}

				if (field.GetType().IsSubclassOf(typeof(InputContainer)))
				{
					childContainerFields.Add(field);
				}
			}
		}

		public void Update(float timeDelta)
		{
			foreach(FieldInfo field in inputFields)
			{
				object value = field.GetValue(this);
				IInputField inputField = (IInputField)value;
				inputField.Update(timeDelta);
			}

			foreach (FieldInfo childContainerField in childContainerFields)
			{
				InputContainer childContainer = (InputContainer)
					childContainerField.GetValue(this);
				childContainer.Update(timeDelta);
			}
		}
	}

	public abstract class MoveInput : InputContainer
	{
		public IVector2DInput direction;
	}
}